home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
magazine
/
drdobbs
/
1990
/
11
/
knowles.asc
< prev
next >
Wrap
Text File
|
1990-10-12
|
44KB
|
1,272 lines
_WINDOWS 3.0 APPLICATION DEVELOPMENT_
by Walter Knowles
[LISTING ONE]
/********************************************************
* FILE: chekmate.ddl
* DESCRIPTION: db_Vista database definition language schema
*********************************************************/
database chekmate {
/* File definition section */
data file checks1 = "chekmate.d01" contains system, payor, payee,
tranPayee, account;
data file checks2 = "chekmate.d02" contains transaction, actual;
data file checks3 = "chekmate.d03" contains budget, distribution;
key file checkKey = "chekmate.k01" contains strPayorName, strAccountName,
strAccountCode, strPayeeCode,
strPayeeName;
/* Ewcord definition section */
record payor {
unique key char strPayorName [35];
char strPayorAddr1 [35];/* single element fields */
char strPayorAddr2 [35];/* are easier in toolbook */
char strPayorCity [20];
char strPayorState [3];
char strPayorZip [10];
char strPayorCtry [10];
char strPayorTel [15];
char cPayorRegAdd; /* values are (a)D(d) and */
char cPayorAccAdd; /*(a)S(k) on exception processing */
char cPayorPayeeAdd;
char cPayorAccess; /* values are C(ode) and N(ame) */
int nPayorYear;
db_addr dbaPayorCurrBank;
int nPayorNextRecur;
}
/* Account covers both balance sheet and income statement accounts. */
record account {
key char strAccountName [35];
key char strAccountCode [15];
char strAccountNumber [15];
char cAccountType; /* A L E I E */
int bAccountTax; /* T= tax related */
int bAccountIsRegister;
}
/* Payee */
record payee {
key char strPayeeName [35];
key char strPayeeCode [15];
char strPayeeAddr1 [35];
char strPayeeAddr2 [35];
char strPayeeCity [20];
char strPayeeState [3];
char strPayeeZip [10];
char strPayeeCtry [10];
char strPayeeTel [15];
/* default account is a set */
char strPayeeMemo [35];
char strPayeeType [10];
}
/* Budget records are owned by the account. */
record budget {
int nBudgetMonth; /* number from 1 to 12 */
long lBudgetAmount;
}
/* Actuals are maintained in order; speeds process of updating register.*/
record actual {
int nActualMonth;
long lActualAmount;
}
/* Transactions are headers for distributions. */
record transaction {
char cTranType; /* check, deposit, etc */
char strTranMemo [35];
int bTranClear; /* T = cleared */
int nTranNumber; /* Check number */
long lTranDate; /* Transaction date as a
"COBOL" date: ccyymmdd */
long lTranAmount;
}
/* Distributions are the balancing entries for transactions. */
record distribution {
long lDistrAmount;
}
/* Set definition section -- Sets with system as parent */
set system_payor {
order ascending;
owner system;
member payor by strPayorName;
}
set system_payeecode {
order ascending;
owner system;
member payee by strPayeeCode;
}
set system_payeename {
order ascending;
owner system;
member payee by strPayeeName;
}
set system_lastData {
order next;
owner system;
member lastData;
}
/* Sets with payor as parent */
set payor_accountcode {
order ascending;
owner payor;
member account by strAccountCode;
}
set payor_accounttypecode {
order ascending;
owner payor;
member account by cAccountType, strAccountCode;
}
set payor_accountname {
order ascending;
owner payor;
member account by strAccountName;
}
/* Sets with account as parent */
set account_budget {
order ascending;
owner account;
member budget by nBudgetMonth;
}
set account_actual {
order ascending;
owner account;
member actual by nActualMonth;
}
set account_distribution {
order next;
owner account;
member distribution;
}
/* account_payee implements default distribution account for payees. */
set account_payee {
order next;
owner account;
member payee;
}
/* sets with payee as owner */
set payee_transaction {
order next;
owner payee;
member transaction;
}
/* sets with actual as owner. */
set actual_transaction_date {
order ascending;
owner actual;
member transaction by lTranDate;
}
set actual_transaction_number {
order ascending;
owner actual;
member transaction by nTranNumber;
}
set actual_transaction_type {
order ascending;
owner actual;
member transaction by cTranType, lTranDate;
}
set actual_distribution {
order next;
owner actual;
member distribution;
}
/* sets with transaction as owner */
set transaction_distribution {
order next;
owner transaction;
member distribution;
}
set transaction_tranPayee {
order next;
owner transaction;
member tranPayee;
}
}
[LISTING TWO]
to handle LINKDLLS
-- use the Windows kernel for memory management
linkdll "kernel.exe"
word globalAlloc (word,dword)
word globalFree (word)
pointer globalLock (word)
word globalReAlloc(word,dword,word)
dword globalSize(word)
word globalUnlock(word)
end
--use ToolBook's file dll for file system access
linkdll "tbkfile.dll"
string getCurrentDirectory(string)
string getCurrentDrive()
end
-- use Raima's db_VISTA dll for database functionality
linkdll "vista.dll"
--except for close,closetask, and opentask, functions are as
--in the db_vista docs (dt_ = d_). The last args are *currenttask,dbn
int dt_close (pointer)
int dt_closetask(pointer)
int dt_connect (int,pointer,int)
int dt_crget (pointer,pointer,int)
--other calls ommitted here
int dt_setro (int,pointer,int)
end
--chekmate.dll is the helper dll for the checking account system
linkdll "chekmate.dll"
--other calls ommitted here
word dbv_EditRegister (word,int,long,int,word,int)
word dbv_GetRegister (word,int,word)
end
end
[LISTING THREE]
to handle InitGlobals
system svhControl, svPtrControl
system svhDBBuffer, svPtrDBBuffer
system svhCurrTask, svPtrCurrTask
set svhControl to GlobalAlloc (66,64) --GHND is 66, size is 64 bytes
set svhDBBuffer to GlobalAlloc (66,256)
set svhCurrTask to GlobalAlloc (66,64)
if svhControl <= 0 or svhDBBuffer <= 0 or svhCurrTask <= 0
--clean up, since allocation failed
send FreeGlobals
send Exit -- shutdown the system
else
--get pointers
set svPtrControl to GlobalLock (svhControl)
set svPtrDBBuffer to GlobalLock (svhDBBuffer)
set svPtrCurrTask to GlobalLock (svhCurrTask)
end
end
to handle FreeGlobals
system svhControl, svPtrControl
system svhDBBuffer, svPtrDBBuffer
system svhCurrTask, svPtrCurrTask
if svhControl is not null and svhControl > 0
get GlobalUnlock (svhControl)
get GlobalFree (svhControl)
end
if svhDBBuffer is not null and svhDBBuffer > 0
get GlobalUnlock (svhDBBuffer)
get GlobalFree (svhDBBuffer)
end
if svhCurrTask is not null and svhCurrTask > 0
get GlobalUnlock (svhCurrTask)
get GlobalFree (svhCurrTask)
end
--clean up globals to make ToolBook suspend rather than GP Fault
set svhControl to null
set svhDBBuffer to null
set svhCurrTask to null
set svPtrControl to null
set svPtrDBBuffer to null
set svPtrCurrTAsk to null
end
[LISTING FOUR]
typedef struct Control {
HANDLE hCurrentTask; //current task structure (DB_TASK)
HANDLE hDataBaseBuffer; //db_Vista's control buffer
// Offscreen image / database address pairs
HANDLE hRegisterImage; //offscreen image of the register field
HANDLE hRegisterDBAArray; //array of database addresses, 1 for each line
//in the register image
// Selector fields storage
HANDLE hPayeeCodeArray; //offscreen image of the payee selector field
HANDLE hPayeeCodeDBAArray; //array of database addresses - payee selector
HANDLE hPayeeNameArray; //offscreen image of the payee selector field
HANDLE hPayeeNameDBAArray; //array of database addresses - payee selector
HANDLE hAccountCodeArray; //offscreen image of account selector field
HANDLE hAccountCodeDBAArray;//array of database addresses - accts. selector
HANDLE hAccountNameArray; //offscreen image of account selector field
HANDLE hAccountNameDBAArray;//array of database addresses - accts selector
HANDLE hRegisterNumbers; //array of deposit, payments, balances
// Database addresses for active records
DB_ADDR dbaCurrPayor; //address of the current payor record
DB_ADDR dbaCurrRegister; //address of the current active register record
DB_ADDR dbaCurrRegisterActual; //address of current month's register
// Database number for concurrency operations
int nDatabaseNumber; //normally 0
} CONTROL;
[LISTING FIVE]
--------------------------
--CONTROL BLOCK ACCESSOR--
--------------------------
to get hControl fField
system svPtrControl
set vOffset to ControlOffset(fField)
set retval to -1
conditions
when char 1 of fField is "h" --handles
set retval to pointerWord(vOffset,svPtrControl)
when chars 1 to 3 of fField is "dba" --db_addrs
set retval to pointerlong(vOffset,svPtrControl)
when char 1 of fField is "n"
set retval to pointerint(vOffset,svPtrControl)
end
return retval
end
to set hControl fField to fVal
system svPtrControl
set vOffset to ControlOffset(fField)
conditions
when char 1 of fField is "h" --handles
get pointerWord(vOffset,svPtrControl,fVal)
when chars 1 to 3 of fField is "dba" --db_addrs
get pointerlong(vOffset,svPtrControl,fVal)
when char 1 of fField is "n"
get pointerint(vOffset,svPtrControl,fVal)
end
end
to get ControlOffset fField
conditions
when char 1 of fField is "h" --handles
conditions
when fField is hCurrentTask
set vOffset to 0
when fField is hDatabaseBuffer
set vOffset to 1
when fField is hRegisterImage
set vOffset to 2
when fField is hRegisterDBAArray
set vOffset to 3
when fField is hRegisterCodeArray
set vOffset to 4
when fField is hRegisterCodeDBAArray
set vOffset to 5
when fField is hRegisterNameArray
set vOffset to 6
when fField is hRegisterNameDBAArray
set vOffset to 7
when fField is hPayeeCodeArray
set vOffset to 8
when fField is hPayeeCodeDBAArray
set vOffset to 9
when fField is hPayeeNameArray
set vOffset to 10
when fField is hPayeeNameDBAArray
set vOffset to 11
when fField is hAccountCodeArray
set vOffset to 12
when fField is hAccountCodeDBAArray
set vOffset to 13
when fField is hAccountNameArray
set vOffset to 14
when fField is hAccountNameDBAArray
set vOffset to 15
when fField is hRegisterNumbers
set vOffset to 16
end
return vOffset*2
when chars 1 to 3 of fField is "dba" --db_addrs
set vbase to 34 -- max(vOffset*2)+2
conditions
when fField is dbaCurrPayor
set vOffset to 0
when fField is dbaCurrRegister
set vOffset to 1
when fField is dbaCurrRegisterActual
set vOffset to 2
end
return vbase+vOffset*4
when char 1 of fField is "n"
set vbase to 46 --vbase + dbaentries * 4
conditions
when fField is "nDatabaseNumber"
set vOffset to 0
end
return vbase+vOffset*2
end
end
[LISTING SIX]
-- Fill selector loads selector text from global memory into selector field
to handle FILLSELECTOR fComboName,fObjectName
set vCurdba to dbv_currentrecord()
set vHText to hControl("h" & fComboName & "Array")
if vhText = 0
get createSelectorList (fComboName)
set vHText to hControl("h" & fComboName & "Array")
end
get globalLock (vHText)
if fObjectName is null
set fObjectName to fComboName
end
set text of (pListID of group fObjectName) to\
pointerString(0, it)
get globalUnLock (vHText)
set dbv_currentrecord() to vCurdba
end
-- createSelectorList loads global memory block with values from appropriate
-- set member fields
to get createSelectorList fArray
system svPtrDbBuffer, svPtrCurrTask
-- first determine what all the database constants are
conditions
when fArray is "RegisterName"
get dt_findfm(20000,svPtrCurrTask,0)
set vSet to 20006
get dt_setom(vSet,20000,svPtrCurrTask,0)
set vField to 1000
-- cases for "RegisterCode", "PayeeCode", "PayeeName", "AccountCode",
-- and "AccountName" are similar
else
return false
end
set vArray to "h" & fArray
--check if the memory is already allocated
if hControl(vArray & "Array") = 0
set vhTextBuffer to globalAlloc(66,1000)
set vhDBABuffer to globalAlloc(66,500)
set hControl(vArray & "Array") to vhTextBuffer
set hControl(vArray & "DBAArray") to vhDBABuffer
else
set vhTextBuffer to hControl(vArray & "Array")
set vhDBABuffer to hControl(vArray & "DBAArray")
end
set vPtrTextBuffer to globalLock(vhTextBuffer)
set vPtrDBABuffer to globalLock(vhDBABuffer)
set vDBAOffset to 0
set vcharCount to 0
get dt_findfm(vSet,svPtrCurrTask,0)
while it = 0
--build the text buffer
get dt_crread(vField,svPtrDbBuffer,svPtrCurrTask,0)
set vline to pointerstring(0,svPtrDbBuffer)
put CRLF after vLine
get pointerstring(vCharCount,vPtrTextBuffer,vLine)
increment vCharCount by charcount(vLine)
--build the db_addr buffer
get dt_crget(svPtrDbBuffer,svPtrCurrTask,0)
get pointerlong(0,svPtrDbBuffer)
get pointerlong(vDBAOffset,vPtrDBABuffer,it)
increment vDBAOffset by 4 -- because DBAs are longs
--get next record
get dt_findnm(vSet,svPtrCurrTask,0)
end
return true
get globalunLock(vhTextBuffer)
get globalunLock(vhDBABuffer)
end
[LISTING SEVEN]
/*****************************************************************************
* dbv_CreateSelectorList--Purpose: Obtains list of available selections for
* a particular chekmate field and save them along with database addresses
* in the chekmate control block.
* Parameters: hControl, HANDLE to the database control block; nSetID, numeric
* identifier for set containing selection list; lField, LONG database field
* number; nHandleOffset, integer offset into the Control block of handle for
* memory where data should be stored.
* Return Value: 0, if no errors; -n, if errors reading database
*/
extern WORD FAR PASCAL dbv_CreateSelectorList(
HANDLE hControl, // Control Block
int nSetID, // database set identifier
LONG lField, // database field number
int hHandleOffset) // offset in Control Block for memory handle
{
int i;
int iError=-1; // error return code
LPCONTROL lpControl=NULL; // control block
DB_TASK DB_FAR *lpTask=NULL; // task pointer
LPHANDLE lpHandle; // handle pointer
if (NULL==hControl)
{
return -1; // control block not initialized
}
// Lock control block so task block can be locked for database call.
lpControl = (LPCONTROL) GlobalLock (hControl);
lpTask = (DB_TASK DB_FAR *) GlobalLock (lpControl->hCurrentTask);
// point to handle in control block for list text.
lpHandle = ((LPHANDLE) lpControl) + hHandleOffset;
iError = LoadSelectorList (lpHandle,lpHandle+1,nSetID,lField,lpTask,
lpControl->nDatabaseNumber);
CleanUp:
GlobalUnlock (lpControl->hCurrentTask);
GlobalUnlock (hControl);
return (iError);
}
/******************************************************************************
* LoadSelectorList--Purpose: Reads database for specified set and transfer
* data from lField into text buffer. Each record a separate text line in
* buffer and database addresses for each record will also be saved.
* Parameters: lphListText, handle to memory for list text; lphListDBA, handle
* to memory for list database addresses; nSetID, numeric identifier for
* database set containing the selection list; lField, LONG database field
* number; lpTask, pointer to database task; nDatabase, database number
* Return Value: 0, if no errors; -n, if errors reading database
*/
int PASCAL LoadSelectorList (
LPHANDLE lphListText, // handle to memory for list text
LPHANDLE lphListDBA, // memory handle for list database adr.
int nSetID, // database set ID
LONG lField, // database field number for list text
DB_TASK DB_FAR *lpTask, // database task
int nDatabase) // database number
{
int iError=-1; // error return code
int nDBA=0; // number of DBA's
int nMaxDBA=0; // maximum number of DBA's used
int nMaxBytes=0; // maximum bytes allowed
LPSTR lpText=NULL; // current text line
DB_ADDR FAR *lpDBA=NULL; // database address value
HANDLE hMem; // handle to reallocated memory block
DB_ADDR lCurDBA; // current database record
// save the current database record
dt_crget ((DB_ADDR FAR *)&lCurDBA,lpTask,nDatabase);
// initialize the text and DBA memory blocks.
if (*lphListText == NULL)
{
*lphListText = GlobalAlloc (DLL_ALLOC,SELECTOR_TEXT_SIZE);
}
if (*lphListDBA == NULL)
{
*lphListDBA = GlobalAlloc (DLL_ALLOC,(LONG)(SELECTOR_DBA_COUNT*sizeof
(DB_ADDR)));
}
if (*lphListText == NULL || *lphListDBA == NULL)
{
goto CleanUp;
}
// initial allocations to set the maximum values and lock the memory blocks.
nMaxDBA = GlobalSize (*lphListDBA) / sizeof(DB_ADDR);
nMaxBytes = GlobalSize (*lphListText);
lpText = GlobalLock (*lphListText);
lpDBA = (DB_ADDR FAR *) GlobalLock (*lphListDBA);
// read the database and fill in the text values
for (iError = dt_findfm (nSetID,lpTask,nDatabase);
iError==S_OKAY;
iError = dt_findnm (nSetID,lpTask,nDatabase))
{
if (nMaxBytes<=MIN_SELECTOR_TEXT_SIZE)
{
// need to allocate more text memory.
lpText = NULL;
GlobalUnlock (*lphListText);
hMem = GlobalReAlloc (*lphListText,
GlobalSize(*lphListText)+SELECTOR_TEXT_SIZE,
GMEM_ZEROINIT);
if (hMem==NULL)
{
iError = -2;
goto CleanUp; // not enough memory
}
*lphListText = hMem; // new handle
lpText = GlobalLock (*lphListText);
nMaxBytes = GlobalSize(*lphListText) - lstrlen (lpText);
lpText += lstrlen(lpText);
}
// read the field contents into the text buffer
dt_crread(lField,lpText,lpTask,nDatabase);
lstrcat (lpText,"\r\n");
lpText += lstrlen(lpText);
// save the DBA of the record
if (nDBA >= nMaxDBA)
{
// need to allocate more DBA memory.
lpDBA = NULL;
GlobalUnlock (*lphListDBA);
hMem = GlobalReAlloc (*lphListDBA,
GlobalSize(*lphListDBA)+SELECTOR_DBA_COUNT*sizeof(DB_ADDR),
GMEM_ZEROINIT);
if (hMem==NULL)
{
iError = -2;
goto CleanUp; // not enough memory
}
*lphListDBA = hMem; // new handle
lpDBA = (DB_ADDR DB_FAR *)GlobalLock (*lphListDBA);
nMaxDBA = GlobalSize(*lphListDBA) - nDBA;
lpDBA += nDBA;
}
dt_crget (lpDBA,lpTask,nDatabase);
lpDBA++;
nDBA++;
}
CleanUp:
// restore the address of the current record
dt_crset ((DB_ADDR far *)&lCurDBA,lpTask,nDatabase);
if (lpText!=NULL)
{
GlobalUnlock (*lphListText);
}
if (lpDBA!=NULL)
{
GlobalUnlock (*lphListDBA);
}
if (iError==S_EOS)
{
iError = S_OKAY;
}
return (iError);
}
[BALANCE MAINTENACE CODE]
typedef struct RegisterNumbers {
long lDeposit; //value of the deposit (may be 0)
long lPayment; //value of the payment (may be 0)
long lBalance; //value of the balance
} REGISTERNUMBERS;
/*******************************************************************************
* UpdateRegisterNumbers
*
* Purpose:
* This routine will update the register payments, deposits and balance
* arrays. Additonally it will copy the information into the register
* text arrays and add the final zero byte to the register text
*
* Parameters:
* lpControl pointer to the control block
*
* Return Value:
* 0 if no errors
*
*/
int PASCAL UpdateRegisterNumbers(
LPCONTROL lpControl) // pointer to the Control block
{
int i;
char cPayment[20], cDeposit[20], cBalance[20];
LONG lBegBal; // begining balance
LPREGISTERNUMBERS lpNumbers; // register numbers
LPREGISTERIMAGE lpImage; // register image block
LPSTR lpLine; // register line image
LONG lPrevBal; // previous balance
lpImage = (LPREGISTERIMAGE) GlobalLock (lpControl->hRegisterImage);
lpNumbers = (LPREGISTERNUMBERS) GlobalLock (lpControl->hRegisterNumbers);
lpLine = (LPSTR) &(lpImage->Text[0]);
// we first go thru the list of numbers and set the balances and then
// we convert the values to strings and place them into the register
// line. Note the register lines are assumed to be blank filled and
// terminated with a CRLF.
for (i=0,lPrevBal=lpNumbers->lBalance;i<lpImage->nLines;i++,lpNumbers++)
{
lPrevBal =
lpNumbers->lBalance = lPrevBal +
lpNumbers->lDeposit - lpNumbers->lPayment;
// convert the values to zero terminated strings
Long2Money (lpNumbers->lPayment,(LPSTR) &(cPayment[0]));
Long2Money (lpNumbers->lDeposit,(LPSTR) &(cDeposit[0]));
Long2Money (lpNumbers->lBalance,(LPSTR) &(cBalance[0]));
wsprintf (lpLine+50," %10s %10s %10s",
(LPSTR) &(cPayment[0]),
(LPSTR) &(cDeposit[0]),
(LPSTR) &(cBalance[0]));
// now add the CRLF to the lines the current zero byte placed in
// the lpLine will be overwritten and no zero byte will be used.
lpLine += lstrlen(lpLine); // positioned at the zero byte
*lpLine++ = '\r';
*lpLine++ = '\n';
// lpLine now positioned correctly for begining of next line
}
// add the final empyt line and a zero byte to terminate the register text field
lstrcat (lpLine,"\r\n");
GlobalUnlock (lpControl->hRegisterImage);
GlobalUnlock (lpControl->hRegisterNumbers);
return (0);
}
/*******************************************************************************
* Long2Money
*
* Purpose:
* convert a long number into a money text string. The numeric value
* is in terms of cents.
*
* Parameters:
* lValue LONG value to be converted
* lpText LPSTR to the text string
*
* Return Value:
* LPSTR pointer to the text string
*
*/
LPSTR PASCAL Long2Money(
LONG lValue, // long value to be converted
LPSTR lpDecimalText) //
{
LPSTR lpStr = lpDecimalText;
// Take care of the sign of the number so that the conversion
// will only have to deal with positive values.
if (lValue <0)
{
lValue = -lValue;
*lpStr++ = '-';
}
// convert the number to characters - note if the value is less
// than 100 then we will want the number to be be converted as
// 0.nn Therefore 100 will be added to the value and then later
// the '1' will be replaced with a '0'.
wsprintf (lpStr,"%li",(LONG) ((lValue<100)?lValue+100:lValue));
// now make room for the decimal point
lpStr += lstrlen(lpStr); // lpStr points to the end of the string
*(lpStr+1) = *lpStr; lpStr--; // terminating character
*(lpStr+1) = *lpStr; lpStr--; // units digit
*(lpStr+1) = *lpStr; // tens digit
*lpStr-- = '.'; // add in the decimal point
if (lValue < 100)
{
*lpStr = '0'; // replace the '1' with a '0' forces leading zero
}
return (lpDecimalText);
}
[REGISTER MAINTENANCE CODE]
/*******************************************************************************
* dbv_GetRegister
*
* Purpose:
* This routine will read the transactions associated with the current
* account for a given month and generates a checkbook register image.
* The image is saved in memory and also set into the toolbook fields
* specified in hFldTable.
*
* Parameters:
* hControl HANDLE to the database control block
* nSetID numeric identifier for database set
* hFldTable HANDLE to the ToolBook field table list
*
* Return Value:
* 0 if no errors
* 1 if error in setting field
* -1 control block not initialized
*
*/
extern WORD FAR PASCAL dbv_GetRegister(
HANDLE hControl, // Control Block
int nSetID) // database set identifier
{
int i;
int iError=0; // error return
LPCONTROL lpControl=NULL; // control block
int nDatabase; // database number
LPREGISTERIMAGE lpImage=NULL; // pointer to the register image block
// Lock the control block so that the task block and the database
// buffer can be obtained. The database buffer will be used to contain
// the individual field values for the current record.
if (NULL==hControl)
{
return -1; // control block not initialized
}
// Lock the control block so that the task block can be locked for the
// database call. Then lock the field table so that we can access
// which ToolBook fields are to be set.
lpControl = (LPCONTROL) GlobalLock (hControl);
lpFldTable = (LPFLDTABLE) GlobalLock(hFldTable);
// Initialize the memory blocks that will be used for the register
// information.
if (0!=(iError=InitRegisterImage(lpControl)))
{
goto CleanUp;
}
// Now we load the register image
if (0!=(iError=LoadRegisterImage (lpControl,nSetID)))
{
goto CleanUp;
}
GlobalUnlock (lpControl->hRegisterImage);
CleanUp:
// all done - now unlock all the allocations
GlobalUnlock (lpFldTable->hBookName);
GlobalUnlock (hFldTable);
GlobalUnlock (hControl);
return 0;
}
/*******************************************************************************
* InitRegisterImage
*
* Purpose:
* This routine will initialize the memory blocks that will contain the
* chekmate register image, the database addresses and the array of the
* deposits, payments and balances for the register.
*
* Parameters:
* lpControl pointer to the control block
*
* Return Value:
* 0 if no errors
* -1 if error allocating the memory
*
*/
int PASCAL InitRegisterImage(
LPCONTROL lpControl) // pointer to the Control block
{
LPREGISTERIMAGE lpImage; // pointer to the register image
// if the handles are currently pointing to memory blocks then we free
// them and re-allocate. This is done just to make life a little easier
if (NULL!=lpControl->hRegisterImage)
{
GlobalFree (lpControl->hRegisterImage);
lpControl->hRegisterImage = NULL;
}
if (NULL!=lpControl->hRegisterDBAArray)
{
GlobalFree (lpControl->hRegisterDBAArray);
lpControl->hRegisterDBAArray = NULL;
}
if (NULL!=lpControl->hRegisterNumbers)
{
GlobalFree (lpControl->hRegisterNumbers);
lpControl->hRegisterNumbers = NULL;
}
// now allocate the space for the register image array
lpControl->hRegisterImage = GlobalAlloc (DLL_ALLOC,
(LONG) sizeof(REGISTERIMAGE)+
(INITIALREGISTERLINES*REGISTERLINESIZE));
if (NULL==lpControl->hRegisterImage)
{
return -1;
}
// now allocate the database address lists
lpControl->hRegisterDBAArray = GlobalAlloc (DLL_ALLOC,
((long) sizeof(DB_ADDR))*((long) INITIALREGISTERLINES));
if (NULL==lpControl->hRegisterDBAArray)
{
return -1;
}
// now allocate the register payments, deposits and balance columns
lpControl->hRegisterNumbers = GlobalAlloc (DLL_ALLOC,
((long) sizeof(REGISTERNUMBERS))*((long)
INITIALREGISTERLINES));
if (NULL==lpControl->hRegisterNumbers)
{
return -1;
}
// initialize the image structure to contain the header information
lpImage = (LPREGISTERIMAGE) GlobalLock (lpControl->hRegisterImage);
lpImage->nMaxLines = INITIALREGISTERLINES;
lpImage->nLines = 0;
GlobalUnlock (lpControl->hRegisterImage);
return (0);
}
/*******************************************************************************
* LoadRegisterImage
*
* Purpose:
* This routine will load the register data from the database.
*
* Parameters:
* lpControl pointer to the control block
* nSetID transaction set id
*
* Return Value:
* 0 if no errors
* -1 if error reading the database
*
*/
int PASCAL LoadRegisterImage(
LPCONTROL lpControl, // pointer to the Control block
int nSetID) // set containing the transaction members
{
int i;
int iError=0; // error return
DB_ADDR lCurDBA; // current database address
actual Actual; // current months value
payee Payee; // current transactions payee
transaction Transaction; // current transaction
int nDatabase; // database number
DB_ADDR lTranDBA; // transaction dba
DB_TASK DB_FAR *lpTask=NULL; // task pointer
DB_ADDR FAR *lpDBA; // database address array
LPREGISTERNUMBERS lpNumbers; // register numbers
LPREGISTERIMAGE lpImage; // register image block
LPSTR lpLine; // line for the register image
// lock the task, the register image, the database addresses array
// and the register number array.
lpTask = (DB_TASK DB_FAR *) GlobalLock (lpControl->hCurrentTask);
nDatabase = lpControl->nDatabaseNumber;
// save the current database record
dt_crget ((DB_ADDR FAR *)&lCurDBA,lpTask,nDatabase);
// now we load up the register data. The fist line in the register is
// the begining balance. We "Fake out" the first line by creating
// a psudeo transaction record for the actual month record.
dt_crset ((DB_ADDR far *)&(lpControl->dbaCurrRegisterActual),lpTask,nDatabase);
dt_setor (nSetID,lpTask,nDatabase);
if (S_OKAY!=(iError=dt_recread((DB_ADDR FAR *)&Actual,lpTask,nDatabase)))
{
goto CleanUp;
}
lpImage = (LPREGISTERIMAGE) GlobalLock (lpControl->hRegisterImage);
lpDBA = (DB_ADDR FAR *) GlobalLock (lpControl->hRegisterDBAArray);
lpNumbers = (LPREGISTERNUMBERS) GlobalLock (lpControl->hRegisterNumbers);
Transaction.cTranType = BBAL; // begining balance
Transaction.lTranDate = 19000001 + (Actual.nActualMonth)*100; // date
Transaction.nTranNumber = 0; // transaction number
Transaction.bTranClear = 0;
Transaction.lTranAmount = Actual.lActualAmount;
lpNumbers->lBalance = Actual.lActualAmount;
dt_crget (lpDBA++,lpTask,nDatabase);
GenerateRegisterLine ((LPTRANSACTION) &Transaction,(LPPAYEE) &Payee,&(lpImage->Text[0]));
lpImage->nLines++;
lpNumbers++;
GlobalUnlock (lpControl->hRegisterImage);
GlobalUnlock (lpControl->hRegisterDBAArray);
GlobalUnlock (lpControl->hRegisterNumbers);
// now step thru the database reading the members of the set and
// generating register lines for them.
for (iError=dt_findfm (nSetID,lpTask,nDatabase),i=1;
iError==S_OKAY;
iError=dt_findnm (nSetID,lpTask,nDatabase),i++)
{
dt_crget ((DB_ADDR FAR *) &lTranDBA,lpTask,nDatabase);
EditRegisterImage (lpControl,i,lTranDBA,nSetID,ADD_TRAN);
}
// now fill in the payment, deposit and balance fields
UpdateRegisterNumbers (lpControl);
CleanUp:
// restore the address of the current record
dt_crset ((DB_ADDR far *)&lCurDBA,lpTask,nDatabase);
GlobalUnlock (lpControl->hCurrentTask);
return (((iError==S_EOS)?S_OKAY:iError));
}
[DB_VISTA SHELL CODE]
-- composite functions for adding and editing records
to get dbv_AddRecord fHDbControl, ftbFields, fRecordID
system svPtrCurrTask,svPtrDbBuffer
get dt_fillnew(fRecordID,svPtrDbBuffer,svPtrCurrTask,0)
get last char of fRecordID
set vStartingField to it *1000 --starting fields of VISTA records are on 1000 boundries
return dbv_EditRecord(fHDbControl, fTbFields, vStartingField)
end
to get dbv_EditRecord fHDbControl, ftbFields, fStartingField
system svPtrCurrTask,svPtrDbBuffer
set vFldCount to itemcount( fTbFields )
step i from 1 to vFldCount
get item i of fTbFields
get pointerstring(0,svPtrDbBuffer,text of field id it)
get dt_crwrite(fStartingField+i,svPtrDbBuffer,svPtrCurrTask,0)
end
return true
end
to get dbv_GetTBFieldArray fhDBControl, fSet, fFieldID, fTbFields
system svPtrDbBuffer,svPtrCurrTask, svCurrAccountDBA
set vCurDBA to dbv_currentrecord()
get dt_findfm(fSet,svPtrCurrTask,0)
if it = 0
set vFldCount to itemcount( fTbFields)
step i from 1 to vFldCount
get dt_crread(fFieldID,svPtrDbBuffer,svPtrCurrTask,0)
set vID to item i of fTbFields
set text of field id vID\
to pointerLong(0,svPtrDbBuffer)/10
format text of field id vID as "0.00"
if dt_findnm(fSet,svPtrCurrTask,0) <> 0
break step
end
end
end
set dbv_currentrecord() to vCurDBA
return true
end
to get dbv_EditTBFieldArray fhDBControl, fhFldTable, fSet, fTbFields
system ,svPtrDbBuffer,svPtrCurrTask, svCurrAccountDBA
set vCurDBA to dbv_currentrecord()
get dt_findfm(fSet,svPtrCurrTask,0)
if it = 0
set vFldCount to itemcount( fTbFields )
step i from 1 to vFldCount
get text of field id (item i of fTbFields)
format it as "0"
get pointerLong(0,svPtrDbBuffer,it)
get dt_crwrite(fFieldID,svPtrDbBuffer,svPtrCurrTask,0)
if dt_findnm(fSet,svPtrCurrTask,0) <> 0
break step
end
end
end
set dbv_currentrecord() to vCurDBA
return true
end
to get dbv_field fType,fFieldNumber
system svhControl,svPtrCurrTask,svPtrDbBuffer
get dt_crread(fFieldNumber,svPtrDbBuffer,svPtrCurrTask,0)
if fType is "CHAR"
set vVal to pointerByte(0,svPtrDbBuffer)
set vVal to ansitochar(vVal)
else
execute "set vVal to pointer" & fType & "(0,svPtrDbBuffer)"
end
return vVal
end
to set dbv_field fType,fFieldNumber to fVal
system svhControl,svPtrCurrTask,svPtrDbBuffer
if ftype is "CHAR"
get chartoansi(fVal)
get pointerbyte (0,svPtrDbBuffer,it)
else
execute "get pointer" & fType & "(0,svPtrDbBuffer,fVal)"
end
get dt_crwrite(fFieldNumber,svPtrDbBuffer,svPtrCurrTask,0)
end
-- db_vISTA shell functions
to get dbv_connectSet fSet
system svPtrCurrTask
get dt_connect(fSet,svPtrCurrTask,0)
end
to get dbv_currentOwnerField fSet, fType, fFieldNumber
system svhControl,svPtrCurrTask,svPtrDbBuffer
get dt_csoread(fSet,fFieldNumber,svPtrDbBuffer,svPtrCurrTask,0)
if fType is "CHAR"
set vVal to pointerByte(0,svPtrDbBuffer)
set vVal to ansitochar(vVal)
else
execute "set vVal to pointer" & fType & "(0,svPtrDbBuffer)"
end
return vVal
end
to set dbv_currentOwnerField fSet, fType, fFieldNumber to fVal
system svhControl,svPtrCurrTask,svPtrDbBuffer
if ftype is "CHAR"
get chartoansi(fVal)
get pointerbyte (0,svPtrDbBuffer,it)
else
execute "get pointer" & fType & "(0,svPtrDbBuffer,fVal)"
end
get dt_csowrite(fSet,fFieldNumber,svPtrDbBuffer,svPtrCurrTask,0)
end
to get dbv_memberCount fSet
system svPtrCurrTask,svPtrDbBuffer
get dt_members(fSet,svPtrDbBuffer,svPtrCurrTask,0)
return (pointerLong(0,svPtrDbBuffer))
end
to get dbv_findFirstMember fSet
system svPtrCurrTask
return dt_findfm(fSet,svPtrCurrTask,0)
end
to get dbv_setOwnerToCurrRec fSet
system svPtrCurrTask
return dt_setor(fSet,svPtrCurrTask,0)
end
to get dbv_currentOwner fSet
system svPtrCurrTask,svPtrDbBuffer
set verror to dt_csoget(fSet,svPtrDbBuffer,svPtrCurrTask,0)
set vdba to pointerlong(0,svPtrDbBuffer)
set sysError to vError
return vdba
end
to set dbv_currentOwner fSet to fDBA
system svPtrCurrTask,svPtrDbBuffer
if fDBA is null or fDBA is 0
get dbv_currentOwner(fSet)
if sysError = 0
get dt_discon(fSet,svPtrCurrTask,0)
end
else
get pointerlong(0,svPtrDbBuffer,fDBA)
get dt_csoset(fSet,svPtrDbBuffer,svPtrCurrTask,0)
end
end
to set dbv_connectOwner fSet to fDBA
system svPtrCurrTask,svPtrDbBuffer
set vCurrDBA to dbv_currentRecord()
if dt_ismember(fSet,svPtrCurrTask,0) = 0
get dt_discon(fSet,svPtrCurrTask,0)
end
if not(fDBA is null or fDBA is 0 )
get pointerlong(0,svPtrDbBuffer,fDBA)
get dt_csoset(fSet,svPtrDbBuffer,svPtrCurrTask,0)
get dbv_currentmember(fSet)
get dbv_currentrecord()
get dbv_currentType()
get dbv_currentOwner(fset)
--get dt_csmset(fSet,)
get dt_connect(fSet,svPtrCurrTask,0)
end
end
to get dbv_currentMember fSet
system svPtrCurrTask,svPtrDbBuffer
set verror to dt_csmget(fSet,svPtrDbBuffer,svPtrCurrTask,0)
set vdba to pointerlong(0,svPtrDbBuffer)
set sysError to vError
return vdba
end
to get dbv_currentType
system svPtrCurrTask,svPtrDbBuffer
get dt_crtype(svPtrDbBuffer,svPtrCurrTask,0)
return pointerint(0,svPtrDbBuffer)
end
to get dbv_currentRecord
system svPtrCurrTask,svPtrDbBuffer
set verror to dt_crget(svPtrDbBuffer,svPtrCurrTask,0)
set vdba to pointerlong(0,svPtrDbBuffer)
set sysError to vError
return vdba
end
to set dbv_currentRecord to fDBA
system svPtrCurrTask,svPtrDbBuffer
get pointerlong(0,svPtrDbBuffer,fDBA)
get dt_crset(svPtrDbBuffer,svPtrCurrTask,0)
end
--dbv_findKey finds the key that matches fKeyVal, or the next higher key that
--contains fKeyVal
to get dbv_findkey fField, fKeyVal, fType
system svPtrDbBuffer,svPtrCurrTask
execute ("get pointer" & fType & "(0,svPtrDbBuffer,fKeyVal)")
get dt_keyfind(fField, svPtrDbBuffer, svPtrCurrTask,0)
if it <> 0
get dt_keynext(fField,svPtrCurrTask,0)
if it <> 0
return -2
end
execute ("get pointer" & fType & "(0,svPtrDbBuffer)")
if fKeyVal is in it
return 0
else
return -1
end
end
end
-- dbv_findrecord navigates through a set to find the nearest member of a set
-- that matches or exceeds fVal
to get dbv_findrecord fSet,fField,fVal,fType
system svPtrDbBuffer,svPtrCurrTask
set vCurrDBA to dbv_currentrecord()
set sysError to -1
set retval to 0
set dbv_currentowner (fSet) to vCurrDBA
get dt_findfm(fSet,svPtrCurrTask,0)
if it = 0
get dt_crread(fField, svPtrDbBuffer, svPtrCurrTask, 0)
execute ("set vdbVal to pointer" & fType &"(0,svPtrDbBuffer)")
while vdbval <= fVal as text
if vdbval is fval
set retval to dbv_currentrecord()
break while
end
get dt_findnm(fSet,svPtrCurrTask,0)
if it <> 0
break while
end
get dt_crread(fField, svPtrDbBuffer, svPtrCurrTask, 0)
set it to "set vdbVal to pointer" & fType &"(0,svPtrDbBuffer)"
execute it
end
end
set dbv_currentrecord() to vCurrDBA
return retval
end